import { isUrl, isEmpty } from "@/utils/common";
import { ResultEnum, ContentTypeEnum } from "@/enums/httpEnum";
import { showErrorMessage, showHttpErrorMessage } from "./msg";
import { openLoading, closeLoading } from "./loading";
import { useEnv } from "@/hooks/useEnv";
import { getToken } from "@/stores/auth";
import useUserStore from "@/stores/user";
import { useRoute } from "@/hooks/useRoute";

const { VITE_APP_BASE_URL } = useEnv();

const requestConfig = {
    baseUrl: VITE_APP_BASE_URL + "/api/",
    // 超时时间
    timeout: 10000,
    // 请求头
    header: {
        "content-type": ContentTypeEnum.JSON,
    },
    // 是否需要loading加载
    loading: false,
    // 重试次数
    retryCount: 0
};

// 添加拦截器
uni.addInterceptor("request", {
    // 拦截前触发
    invoke(options: UniApp.RequestOptions) {
        if (!isUrl(options.url)) options.url = requestConfig.baseUrl + options.url;
        options.timeout = requestConfig.timeout;
        options.header = Object.assign(options.header?options.header:{}, requestConfig.header);
        if (requestConfig.loading) openLoading();

        const token = getToken();
        // 请求头添加token
        if (token) options.header.Authorization = token;
    },
});

// 后端返回通用结构
type Data<T> = {
    code: number;
    msg: string;
    data: T;
};

// 检验登录过期
const checkLoginExpire = (data: any) => {
    // 检验token过期重新登录
    if (data.code === ResultEnum.EXPIRE) {
        useUserStore().logout(false);
        useRoute().jumpTo({ url: '/pages/login/login' });
    }
};

const request = {
    get<T = any>(url: string, data?: any, header?: object, config?:any): Promise<T> {
        return request.request("GET", url, data, header, config);
    },
    post<T = any>(url: string, data?: any, header?: object, config?:any): Promise<T> {
        return request.request("POST", url, data, header, config);
    },
    put<T = any>(url: string, data?: any, header?: object, config?:any): Promise<T> {
        return request.request("PUT", url, data, header, config);
    },
    delete<T = any>(url: string, data?: any, header?: object, config?:any): Promise<T> {
        return request.request("DELETE", url, data, header, config);
    },
    upload<T = any>(
        url: string,
        name: string = "file",
        filePath: string = "",
        data?: any,
        callBack?: any
    ) {
        return new Promise((resolve, reject) => {
            uni.uploadFile({
                url: requestConfig.baseUrl + url,
                filePath: filePath,
                name: name,
                timeout: 3000,
                header: {
                    Authorization: getToken(),
                },
                formData: data || "",
                dataType: "json",
                responseType: "json",
                success: (res) => {
                    if (res.statusCode >= 200 && res.statusCode < 300) {
                        const apiData = JSON.parse(res.data);
                        if (apiData.code === ResultEnum.SUCCESS) {
                            if (callBack) callBack(apiData.data);
                            resolve(apiData.data);
                        } else {
                            showErrorMessage(apiData);
                            checkLoginExpire(apiData);
                            reject(apiData);
                        }
                    } else {
                        showHttpErrorMessage(res);
                        reject(res);
                    }
                },
                fail(err) {
                    showErrorMessage({ msg: "上传失败，请稍后再试~" });
                    reject(err);
                },
                complete: () => {
                    if (requestConfig.loading) closeLoading();
                },
            });
        });
    },
    request<T = any>(
        method:
            | "OPTIONS"
            | "GET"
            | "HEAD"
            | "POST"
            | "PUT"
            | "DELETE"
            | "TRACE"
            | "CONNECT" = "GET",
        url: string,
        data?: any,
        header?: object,
        config?:any
    ): Promise<T> {
        const options: UniApp.RequestOptions = {
            url: url,
            method: method,
            data: data,
            header: header,
        };
        // 返回 Promise 对象
        return new Promise((resolve, reject) => {
            uni.request({
                ...options,
                success(res) {
                    if (res.statusCode >= 200 && res.statusCode < 300) {
                        const apiData = res.data as Data<T>;
                        if (apiData.code === ResultEnum.SUCCESS) {
                            resolve(apiData.data);
                        } else {
                            showErrorMessage(apiData);
                            checkLoginExpire(apiData);
                            reject(apiData);
                        }
                    } else {
                        showHttpErrorMessage(res);
                        reject(res);
                    }
                },
                fail(err) {
                    // 请求重试检验
                    let retryCount = isEmpty(config)?requestConfig.retryCount:config?.retryCount;
                    if(retryCount > 0) {
                        request.request(method, url, data, header, {retryCount: retryCount - 1});
                        return;
                    }
                    showErrorMessage({ msg: "网络错误，请稍后再试~" });
                    reject(err);
                },
                complete: () => {
                    if (requestConfig.loading) closeLoading();
                },
            });
        });
    },
};

export default request;
